package com.hifar.utils;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Excel 模板填充工具类（支持占位符替换 + 表格数据填充）
 */
public class ExcelTemplateReplaceUtil {

    /**
     * 单个占位符替换（如 {name}）
     *
     * @param templateBytes 模板字节流
     * @param replaceMap    替换映射，如 {"name": "张三", "drawingNo": "D1001"}
     * @return 替换后的 Excel 字节流
     */
    public static byte[] fillExcelTemplateWithPlaceholders(byte[] templateBytes, Map<String, String> replaceMap) throws IOException {
        return processWorkbook(templateBytes, workbook -> {
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                Sheet sheet = workbook.getSheetAt(i);
                for (Row row : sheet) {
                    for (Cell cell : row) {
                        if (cell.getCellType() == CellType.STRING) {
                            String value = cell.getStringCellValue();
                            for (Map.Entry<String, String> entry : replaceMap.entrySet()) {
                                value = value.replace("{" + entry.getKey() + "}", entry.getValue());
                            }
                            cell.setCellValue(value);
                        }
                    }
                }
            }
        });
    }

    /**
     * 列表数据替换，适用于表格数据填充（支持多字段按列名填充）
     *
     * @param templateBytes 模板字节流
     * @param dataList      数据列表，如 List<PartsTaskVo>
     * @param startRowIdx   开始填充的行索引（从 0 开始）
     * @param fieldMapping  Java 对象字段名 -> Excel 列名 映射，如 {"stepName": "步骤名称"}
     * @return 替换后的 Excel 字节流
     */
    public static <T> byte[] fillExcelTemplateWithListData(byte[] templateBytes, List<T> dataList, int startRowIdx, Map<String, String> fieldMapping) throws IOException {
        Objects.requireNonNull(dataList, "数据列表不能为空");
        if (dataList.isEmpty()) throw new IllegalArgumentException("数据列表不能为空");

        return processWorkbook(templateBytes, workbook -> {
            Sheet sheet = workbook.getSheetAt(0); // 默认操作第一个 sheet

            // 获取表头行（假设在 startRowIdx 上一行）
            Row headerRow = sheet.getRow(startRowIdx - 1);
            if (headerRow == null) {
                throw new IllegalStateException("未找到表头行，请确认 startRowIdx 设置正确");
            }

            // 构建列名到列索引的映射
            Map<String, Integer> columnNameToIndex = new HashMap<>();
            for (Cell cell : headerRow) {
                if (cell.getCellType() == CellType.STRING) {
                    columnNameToIndex.put(cell.getStringCellValue(), cell.getColumnIndex());
                }
            }

            // 清除旧数据
            int lastRowNum = sheet.getLastRowNum();
            for (int i = lastRowNum; i > startRowIdx; i--) {
                sheet.removeRow(sheet.getRow(i));
            }

            // 填充新数据
            for (int i = 0; i < dataList.size(); i++) {
                Row newRow = sheet.createRow(startRowIdx + i);
                T data = dataList.get(i);

                for (Map.Entry<String, String> entry : fieldMapping.entrySet()) {
                    String fieldName = entry.getKey();
                    String columnLabel = entry.getValue();

                    Integer columnIndex = columnNameToIndex.get(columnLabel);
                    if (columnIndex == null) {
                        throw new IllegalArgumentException("未找到列名 [" + columnLabel + "] 的表头，请检查模板和 fieldMapping 配置");
                    }

                    Object value = getField(data, fieldName);
                    if (value != null) {
                        Cell cell = newRow.createCell(columnIndex);
                        setCellValue(cell, value);
                        // 可选：复制样式
//                        copyRowStyle(headerRow, newRow);
                    }
                }
            }
        });
    }


    /**
     * 二合一替换方法：同时支持单个占位符替换和列表数据替换
     *
     * @param templateBytes 模板字节流
     * @param replaceMap    单个占位符替换映射（如 {"name": "张三"}）
     * @param dataList      列表数据（如 List<PartsTaskVo>）
     * @param startRowIdx   开始填充的行索引
     * @param fieldMapping  Java字段名 -> Excel列名 映射（如 {"name": "零件名称"}）
     * @return 替换后的 Excel 字节流
     */
    public static <T> byte[] fillExcelTemplate(byte[] templateBytes, Map<String, String> replaceMap, List<T> dataList, int startRowIdx, Map<String, String> fieldMapping) throws IOException {
        byte[] afterPlaceholder = fillExcelTemplateWithPlaceholders(templateBytes, replaceMap);
        return fillExcelTemplateWithListData(afterPlaceholder, dataList, startRowIdx, fieldMapping);
    }

    /**
     * 公共 Workbook 处理逻辑
     */
    private static byte[] processWorkbook(byte[] templateBytes, WorkbookProcessor processor) throws IOException {
        try (Workbook workbook = new XSSFWorkbook(new ByteArrayInputStream(templateBytes))) {
            processor.process(workbook);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            workbook.write(bos);
            return bos.toByteArray();
        }
    }

    @FunctionalInterface
    private interface WorkbookProcessor {
        void process(Workbook workbook) throws IOException;
    }

    /**
     * 反射获取对象字段值
     */
    private static Object getField(Object obj, String fieldName) {
        try {
            return obj.getClass().getMethod("get" + capitalize(fieldName)).invoke(obj);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException("无法获取字段 [" + fieldName + "] 的值", e);
        }
    }

    private static String capitalize(String str) {
        if (str == null || str.isEmpty()) return str;
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    /**
     * 复制行样式（字体、颜色等）
     */
    private static void copyRowStyle(Row fromRow, Row toRow) {
        for (int i = 0; i < fromRow.getLastCellNum(); i++) {
            Cell fromCell = fromRow.getCell(i);
            Cell toCell = toRow.createCell(i);

            if (fromCell != null && fromCell.getCellType() == CellType.STRING) {
                CellStyle newStyle = toRow.getSheet().getWorkbook().createCellStyle();
                Font font = toRow.getSheet().getWorkbook().getFontAt(fromCell.getCellStyle().getFontIndex());
                newStyle.cloneStyleFrom(fromCell.getCellStyle());
                newStyle.setFont(font);
                toCell.setCellStyle(newStyle);
                toCell.setCellValue(fromCell.getStringCellValue());
            }
        }
    }

    /**
     * 向指定名称的隐藏 Sheet 写入一个 JSON 字符串（例如写入 A1 单元格）
     *
     * @param workbookBytes   Excel 文件字节流
     * @param sheetName       隐藏的 Sheet 名称
     * @param jsonString      要写入的 JSON 字符串
     * @param protectPassword Sheet 保护密码（可为 null）
     * @return 处理后的 Excel 字节流
     */
    public static byte[] writeJsonToHiddenSheet(
            byte[] workbookBytes,
            String sheetName,
            String jsonString,
            String protectPassword) throws Exception {

        try (Workbook workbook = new XSSFWorkbook(new ByteArrayInputStream(workbookBytes))) {
            Sheet hiddenSheet = workbook.getSheet(sheetName);
            if (hiddenSheet == null) {
                throw new IllegalArgumentException("未找到名为 [" + sheetName + "] 的 Sheet");
            }

            // 清空旧数据（可选）
            for (int i = hiddenSheet.getLastRowNum(); i >= 0; i--) {
                hiddenSheet.removeRow(hiddenSheet.getRow(i));
            }

            // 写入 JSON 到 A1 单元格
            Row row = hiddenSheet.createRow(0);
            Cell cell = row.createCell(0);
            cell.setCellValue(jsonString);

            // 设置隐藏
            int sheetIndex = workbook.getSheetIndex(hiddenSheet);
            workbook.setSheetHidden(sheetIndex, true);

            // 设置保护（可选密码）
            if (protectPassword != null && !protectPassword.isEmpty()) {
                hiddenSheet.protectSheet(protectPassword);
            }

            // 输出为字节流
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            workbook.write(byteArrayOutputStream);
            return byteArrayOutputStream.toByteArray();
        }
    }



    /**
     * 设置单元格值（支持多种类型）
     */
    private static void setCellValue(Cell cell, Object value) {
        if (value instanceof String) {
            cell.setCellValue((String) value);
        } else if (value instanceof Integer) {
            cell.setCellValue((Integer) value);
        } else if (value instanceof Double) {
            cell.setCellValue((Double) value);
        } else if (value instanceof Boolean) {
            cell.setCellValue((Boolean) value);
        } else {
            cell.setCellValue(value != null ? value.toString() : "");
        }
    }

}
